package userInterface.imageCapture;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

import logging.*;
import robot.*;

/**
 * A semi-transparent, screen-sized {@link javax.swing.JDialog JDialog} which captures a user-defined rectangular segment.
 * User selections are confirmed with {@link userInterface.imageCapture.DialogCaptureConfirmation DialogCaptureConfirmation}.
 * @author BDS
 */
class DialogCaptureOverlay extends JDialog
{
    private static final long serialVersionUID = 1L;
    
    private KeyAdapter captureOverlayKeyAdapter;
	private MouseAdapter captureOverlayMouseAdapter;
	private MouseMotionAdapter captureOverlayMouseMotionAdapter;
	
	private JPanel pnlTransparent;
	
	private Point dragPoint;
	private String capturedImageName;
	
	/**
	 * Class constructor.
	 */
	public DialogCaptureOverlay()
	{
        captureOverlayKeyAdapter = new CaptureOverlayKeyAdapter();
        captureOverlayMouseAdapter = new CaptureOverlayMouseAdapter();
        captureOverlayMouseMotionAdapter = new CaptureOverlayMouseMotionAdapter();

	    setUndecorated(true);
	    setOpacity(0.20F);
	    setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds());
	    setAlwaysOnTop(true);
	    setModal(true);
        addKeyListener(captureOverlayKeyAdapter);

		pnlTransparent = new PanelTransparent();
		pnlTransparent.setOpaque(false);
		pnlTransparent.addMouseListener(captureOverlayMouseAdapter);
		pnlTransparent.addMouseMotionListener(captureOverlayMouseMotionAdapter);
		add(pnlTransparent);
		
		dragPoint = null;
		capturedImageName = null;
	}
	
	/**
	 * Displays a crosshair cursor when the dialog is visible.
	 * @param visible If <code>true</code>, a crosshair cursor is used.
	 */
	@Override
	public void setVisible(boolean visible)
	{
        if (visible)
        {
            setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        }
        else
        {
            setCursor(Cursor.getDefaultCursor());
        }
        
        super.setVisible(visible);
	}
	
	/**
	 * Gets the filename of the captured image.
	 * @return The filename of the captured image.
	 */
	public String getCapturedImageName()
	{
	    return capturedImageName;
	}
	
	/**
	 * Utility function to obtain a {@link java.awt.Rectangle Rectangle} representing the user's current selection.
	 * @return <ul>
	 *             <li>A {@link java.awt.Rectangle Rectangle} representing the user's current selection.</li>
	 *             <li><code>null</code> if nothing is selected.</li>
	 *         </ul>
	 */
	private Rectangle getSelectedArea()
	{
	    Rectangle selectedArea = null;
	    
	    if (dragPoint != null)
	    {
    	    Point initialPoint = new Point((int)Math.min(dragPoint.getX(), MouseInfo.getPointerInfo().getLocation().getX()),
                                           (int)Math.min(dragPoint.getY(), MouseInfo.getPointerInfo().getLocation().getY()));
            int width = Math.min((int)Math.abs(dragPoint.getX() - MouseInfo.getPointerInfo().getLocation().getX()),
                                 (int)(Toolkit.getDefaultToolkit().getScreenSize().width * 0.7));
            int height = Math.min((int)Math.abs(dragPoint.getY() - MouseInfo.getPointerInfo().getLocation().getY()),
                                  (int)(Toolkit.getDefaultToolkit().getScreenSize().height * 0.7));
    	
            selectedArea = new Rectangle((int)initialPoint.getX(), (int)initialPoint.getY(), width, height);
	    }

	    return selectedArea;
	}
	
    /**
     * Primary {@link javax.swing.JPanel JPanel} for {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay}.
     * @author BDS
     */
	private class PanelTransparent extends JPanel
	{
        private static final long serialVersionUID = 1L;

        /**
         * Paints the {@link java.awt.Component Component} as well as a rectangle representing the user's current selection.
         * @param graphics The {@link java.awt.Graphics Graphics} object to protect.
         */
        @Override
        public void paintComponent(Graphics graphics)
        {
            super.paintComponent(graphics);

            Rectangle selectedArea = getSelectedArea();
            if (selectedArea != null)
            {
                graphics.drawRect((int)selectedArea.getX(),
                                  (int)selectedArea.getY(),
                                  (int)selectedArea.getWidth(),
                                  (int)selectedArea.getHeight());
            }
        }
	}
    
    /**
     * {@link java.awt.event.KeyAdapter KeyAdapter} for {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay} key events.
     * @author BDS
     */
    private class CaptureOverlayKeyAdapter extends KeyAdapter
    {
        /**
         * Hides the {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay}.
         * @param keyEvent The triggering {@link java.awt.event.KeyEvent KeyEvent}.
         */
        @Override
        public void keyTyped(KeyEvent keyEvent)
        {
            SwingUtilities.getRoot(keyEvent.getComponent()).setVisible(false);
        }
    }
	
    /**
     * {@link java.awt.event.MouseAdapter MouseAdapter} for {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay} mouse click events.
     * @author BDS
     */
	private class CaptureOverlayMouseAdapter extends MouseAdapter
	{   
	    /**
	     * Executes specific logic based on the following {@link java.awt.event.MouseEvent MouseEvents}:
	     * <ul>
	     *     <li>Left click - stores the click point.</li>
	     *     <li>Right click - hides the {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay}.</li>
	     * </ul>
	     */
	    @Override
        public void mousePressed(MouseEvent mouseEvent)
        {
	        if (mouseEvent.getButton() == MouseEvent.BUTTON1)
	        {
                dragPoint = mouseEvent.getPoint();
	        }
	        else if (mouseEvent.getButton() == MouseEvent.BUTTON3)
	        {
	            setVisible(false);
	        }
	        
	        capturedImageName = null;
        }

	    /**
	     * <ul>
	     *     <li>Hides the {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay}.</li>
	     *     <li>Captures an image representing the selected area of the screen.</li>
	     *     <li>Displays the {@link userInterface.imageCapture.DialogCaptureConfirmation DialogCaptureConfirmation}.</li>
	     * </ul>
	     * @param mouseEvent The triggering {@link java.awt.event.MouseEvent MouseEvent}.
	     */
        @Override
        public void mouseReleased(MouseEvent mouseEvent)
        {
            setVisible(false);
            
            BufferedImage capturedImage = null;
            try
            {
                Rectangle selectedArea = getSelectedArea();
                selectedArea.setSize((int)selectedArea.getWidth() + 1, (int)selectedArea.getHeight() + 1);
                
                capturedImage = new ExecutionRobot().createScreenCapture(selectedArea);
            }
            catch (AWTException exception)
            {
                Logger.logException(exception);
            }
            dragPoint = null;
            
            DialogCaptureConfirmation captureConfirmation = new DialogCaptureConfirmation(capturedImage);
            captureConfirmation.setVisible(true);
            capturedImageName = captureConfirmation.getCapturedImageName();
        }
	}
	
	/**
	 * {@link java.awt.event.MouseMotionAdapter MouseMotionAdapter} for {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay} mouse movement events.
	 * @author BDS
	 */
	private class CaptureOverlayMouseMotionAdapter extends MouseMotionAdapter
    {
	    /**
	     * Repaints the {@link userInterface.imageCapture.DialogCaptureOverlay DialogCaptureOverlay}
	     * in order to indicate the user's current selection.
	     * @param mouseEvent The triggering {@link java.awt.event.MouseEvent MouseEvent}.
	     */
        @Override
        public void mouseDragged(MouseEvent mouseEvent)
        {
            repaint();
        }
    }
}
